<template>
	<view class="birthday-picker" v-if="md.done">
		<!-- 半透明遮罩 -->
		<view
			class="mask"
			:class="{ show: md.open }"
			:style="{
				backgroundColor: props.maskColor,
				width: clientWidth + 'px',
				left: windowWidth / 2 - clientWidth / 2 + 'px'
			}"
			@touchmove.stop.prevent
			catchtouchmove="true"
			@click="md.open = false"
		></view>
		<!-- 容器 -->
		<view
			class="wrap"
			:class="{ show: md.open }"
			:style="{ width: clientWidth + 'px', left: windowWidth / 2 - clientWidth / 2 + 'px' }"
		>
			<!-- 头部视图 -->
			<view class="picker-header" @touchmove.stop.prevent catchtouchmove="true">
				<!-- 公历/农历切换 -->
				<view
					v-if="md.menus.length > 1"
					class="change"
					:style="{ border: '1px solid ' + props.themeColor }"
				>
					<template v-if="md.menus[0] === MENU.solar">
						<view
							:class="!md.isLunar ? 'active' : ''"
							:style="!md.isLunar ? { backgroundColor: props.themeColor } : {}"
							@click="_onLunar(false)"
						>
							公历
						</view>
						<view
							:class="md.isLunar ? 'active' : ''"
							:style="md.isLunar ? { backgroundColor: props.themeColor } : {}"
							@click="_onLunar(true)"
						>
							农历
						</view>
					</template>
					<template v-if="md.menus[0] === MENU.lunar">
						<view
							:class="md.isLunar ? 'active' : ''"
							:style="md.isLunar ? { backgroundColor: props.themeColor } : {}"
							@click="_onLunar(true)"
						>
							农历
						</view>
						<view
							:class="!md.isLunar ? 'active' : ''"
							:style="!md.isLunar ? { backgroundColor: props.themeColor } : {}"
							@click="_onLunar(false)"
						>
							公历
						</view>
					</template>
				</view>
				<view v-if="md.menus.length <= 1" class="change" />
				<!-- 标题 -->
				<text>{{ props.title }}</text>
				<!-- 确定按钮 -->
				<view class="submit">
					<view />
					<text :style="{ color: props.themeColor }" @click="_onSubmit()">确 定</text>
				</view>
			</view>
			<!-- 公历选择器 -->
			<view class="picker-body" v-if="!md.isLunar">
				<picker-view :value="md.value" @change="_onChange" indicator-class="select-line">
					<!-- 年 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.cYears"
							:key="item"
							:class="md.selYear.num == item.num ? 'select-item' : 'column-item'"
						>
							{{ item.num }}年
						</view>
					</picker-view-column>
					<!-- 月 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.selYear.months"
							:key="item"
							:class="md.selMonth.num == item.num ? 'select-item' : 'column-item'"
						>
							{{ zeroPadding(item.num) }}月
						</view>
					</picker-view-column>
					<!-- 日 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.selMonth.days"
							:key="item"
							:class="md.selDay == item ? 'select-item' : 'column-item'"
						>
							{{ zeroPadding(item) }}日
						</view>
					</picker-view-column>
				</picker-view>
			</view>
			<!-- 农历选择器 -->
			<view class="picker-body" v-if="md.isLunar">
				<picker-view :value="md.value" @change="_onChange" indicator-class="select-line">
					<!-- 年 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.lYears"
							:key="item"
							:class="md.selYear.num == item.num ? 'select-item' : 'column-item'"
						>
							{{ item.num + item.name }}年
						</view>
					</picker-view-column>
					<!-- 月 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.selYear.months"
							:key="item"
							:class="md.selMonth.num == item.num ? 'select-item' : 'column-item'"
						>
							{{ zeroPadding(item.name) }}
						</view>
					</picker-view-column>
					<!-- 日 -->
					<picker-view-column class="picker-view-column">
						<view
							v-for="(item, index) in md.selMonth.days"
							:key="item"
							:class="md.selDay == item ? 'select-item' : 'column-item'"
						>
							{{ zeroPadding(md.selMonth.names[index]) }}
						</view>
					</picker-view-column>
				</picker-view>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, reactive, onMounted, watch } from 'vue';
import { onReady } from '@dcloudio/uni-app';
import calendar from 'js-calendar-converter';

const clientWidth = document?.body.clientWidth || uni.getSystemInfoSync().windowWidth; //移动端宽度
const windowWidth = uni.getSystemInfoSync().windowWidth; //窗口宽度

const props = defineProps({
	// 显示公历、农历切换按钮（默认都显示）
	menus: {
		type: Array,
		default: ['solar', 'lunar']
	},
	// 选择器标题
	title: {
		type: String,
		default: '生日选择器'
	},
	// 主题色
	themeColor: {
		type: String,
		default: '#ff0000'
	},
	// 遮罩颜色
	maskColor: {
		type: String,
		default: 'rgba(0, 0, 0, 0)'
	},
	// 起始时间（公历，不早于1901年）
	startDate: {
		type: Date,
		default: new Date(1901, 0, 1)
	},
	// 结束时间（公历，不晚于2100年）
	endDate: {
		type: Date,
		default: new Date()
	},
	// 默认选中时间（公历）
	defaultDate: {
		type: Date,
		default: new Date()
	},
	// 是否默认选中农历，默认公历（没有切换按钮时设置无效）
	defaultLunar: {
		type: Boolean,
		default: false
	}
});
const emit = defineEmits(['submit']);
defineExpose({
	show,
	hide
});

const MENU = {
	solar: 'solar',
	lunar: 'lunar'
};
const md = reactive({
	// 是否显示
	open: false,
	done: false,
	// 是否为农历
	isLunar: false,
	// 默认选中日期
	defaultDate: new Date(),
	// 选择器选中的索引
	value: [0, 0, 0],
	// 切换按钮
	menus: [],

	// 公历年数据[{"num":1990,"months":[{"num":1,days:[1,2]}]}]
	cYears: [],
	// 农历年数据[{"num":1990,"name":"庚子",months":[{"num":"1","name":"正月","isLeap":false,days:[1,2],names:["初一","初二"]}]}]
	lYears: [],

	// 选中的年{"num":1990,"months":[...]}
	selYear: {},
	// 选中的月{"num":1,"days":[...]}
	selMonth: {},
	// 选中的日num
	selDay: ''
});

onMounted(() => {
	init();
});

// 初始化默认值
function init() {
	if (md.cYears.length == 0 && md.lYears.length == 0) {
		// 首次打开才赋值
		md.isLunar = props.defaultLunar;
		md.defaultDate = props.defaultDate;

		var validMenus = Object.values(props.menus);
		var menus = [];
		for (var i = 0; i < props.menus.length; i++) {
			var name = props.menus[i];
			if (validMenus.includes(name)) {
				menus.push(name);
			}
		}
		if (menus.length === 0) {
			// 都没配置的话，默认都显示
			menus.push(MENU.solar);
			menus.push(MENU.lunar);
		}
		md.menus = menus;
		if (menus.length === 1) {
			// 只有一个日历类型，则重新赋值isLunar
			md.isLunar = menus.includes(MENU.lunar);
		}
	}
	initYears();
	setSelectValue();
	md.done = true;
}

// 初始化年份
function initYears() {
	// 设置的开始年份、结束年份
	var startYear, endYear;
	// 选择器开始的年、月、日
	var sy, sm, sd;
	// 选择器结束的年、月、日
	var ey, em, ed;
	// 默认选中的年、月、日
	var dy, dm, dd;

	// 下面可以优化为，选中年时，先获取月列表，有则展示，无责创建；日列表同理
	if (md.isLunar) {
		// 农历年
		var defaultObj = calendar.solar2lunar(
			md.defaultDate.getFullYear(),
			md.defaultDate.getMonth() + 1,
			md.defaultDate.getDate()
		);
		dy = defaultObj.lYear;
		dm = defaultObj.lMonth;
		dd = defaultObj.lDay;
		var dl = defaultObj.isLeap;

		if (md.lYears.length > 0) {
			// 已经创建好了
			if (md.open) {
				// 是切换公历/农历，需要找到已选中日期的索引
				var stop = false;
				for (var i = 0; i < md.lYears.length; i++) {
					var year = md.lYears[i];
					if (year.num === dy) {
						for (var j = 0; j < year.months.length; j++) {
							var month = year.months[j];
							if (month.num === dm && month.isLeap == dl) {
								for (var k = 0; k < month.days.length; k++) {
									if (month.days[k] === dd) {
										md.value[0] = i;
										md.value[1] = j;
										md.value[2] = k;
										stop = true;
										break;
									}
								}
							}
						}
						if (stop) {
							break;
						}
					}
					if (stop) {
						break;
					}
				}
			}
			return;
		}
		// 开始日期，转农历
		var startObj = calendar.solar2lunar(
			props.startDate.getFullYear(),
			props.startDate.getMonth() + 1,
			props.startDate.getDate()
		);
		sy = startObj.lYear;
		sm = startObj.lMonth;
		sd = startObj.lDay;
		var sl = startObj.isLeap;

		// 结束日期，转农历
		var endObj = calendar.solar2lunar(
			props.endDate.getFullYear(),
			props.endDate.getMonth() + 1,
			props.endDate.getDate()
		);
		ey = endObj.lYear;
		em = endObj.lMonth;
		ed = endObj.lDay;
		var el = endObj.isLeap;

		startYear = Math.max(sy, 1900);
		endYear = Math.min(ey, 2099);

		const years = [];
		for (var i = startYear; i <= endYear; i++) {
			if (i === dy) {
				// 默认选中年
				md.value[0] = i - startYear;
			}
			// 获取本年的闰月，0为没有闰月
			var leapMonth = calendar.leapMonth(i);
			const months = [];
			for (var j = 1; j <= 12; j++) {
				if (i === dy && j === dm) {
					// 默认选中月（本年无闰月||月份小于闰月||（闰月数字相同&&默认选中不是闰月））
					md.value[1] =
						j - (leapMonth <= 0 || j < leapMonth || (j === leapMonth && !dl) ? 1 : 0);
				}
				var k = 1;
				var dayCount = calendar.monthDays(i, j);
				if (i === startYear) {
					// 不能早于最小日期
					if (j < sm) {
						continue;
					} else if (j === sm) {
						k = sd;
					}
				}
				if (i === endYear) {
					// 不能晚于最大日期
					if (j > em) {
						break;
					} else if (j === em) {
						dayCount = ed;
					}
				}
				const days = [];
				const names = [];
				for (k; k <= dayCount; k++) {
					if (i === dy && j === dm && k === dd && !dl) {
						// 默认选中日（非闰月）
						md.value[2] = k - 1;
					}
					days.push(k);
					names.push(calendar.toChinaDay(k));
				}
				months.push({
					num: j,
					name: calendar.toChinaMonth(j),
					days: days,
					names: names,
					isLeap: false
				});
				if (j === leapMonth) {
					// 是闰月，再添加一次
					var k = 1;
					var dayCount = calendar.leapDays(i);
					const days = [];
					const names = [];
					for (k; k <= dayCount; k++) {
						if (i === dy && j === dm && k === dd && dl) {
							// 默认选中日（闰月）
							md.value[2] = k - 1;
						}
						days.push(k);
						names.push(calendar.toChinaDay(k));
					}
					months.push({
						num: j,
						name: '闰' + calendar.toChinaMonth(j),
						days: days,
						names: names,
						isLeap: true
					});
				}
			}
			years.push({
				num: i,
				name: calendar.toGanZhiYear(i),
				months: months,
				lunar: true // 标识是农历数据
			});
		}
		md.lYears = years;
	} else {
		// 公历年
		dy = md.defaultDate.getFullYear();
		dm = md.defaultDate.getMonth() + 1;
		dd = md.defaultDate.getDate();

		if (md.cYears.length > 0) {
			// 已经创建好了
			if (md.open) {
				// 是切换公历/农历，需要找到已选中日期的索引
				var stop = false;
				for (var i = 0; i < md.cYears.length; i++) {
					var year = md.cYears[i];
					if (year.num === dy) {
						for (var j = 0; j < year.months.length; j++) {
							var month = year.months[j];
							if (month.num === dm) {
								for (var k = 0; k < month.days.length; k++) {
									if (month.days[k] === dd) {
										md.value[0] = i;
										md.value[1] = j;
										md.value[2] = k;
										stop = true;
										break;
									}
								}
							}
						}
						if (stop) {
							break;
						}
					}
					if (stop) {
						break;
					}
				}
			}
			return;
		}

		sy = props.startDate.getFullYear();
		sm = props.startDate.getMonth() + 1;
		sd = props.startDate.getDate();

		ey = props.endDate.getFullYear();
		em = props.endDate.getMonth() + 1;
		ed = props.endDate.getDate();

		startYear = Math.max(sy, 1900);
		endYear = Math.min(ey, 2099);

		const years = [];
		for (var i = startYear; i <= endYear; i++) {
			if (i === dy) {
				// 默认选中年
				md.value[0] = i - startYear;
			}
			// 是闰年
			var isLeap = i % 4 === 0;
			const months = [];
			for (var j = 1; j <= 12; j++) {
				if (i === dy && j === dm) {
					// 默认选中月
					md.value[1] = j - 1;
				}
				var k = 1;
				var dayCount = j == 2 && isLeap ? 29 : calendar.solarDays(i, j);
				if (i === startYear) {
					// 不能早于最小日期
					if (j < sm) {
						continue;
					} else if (j === sm) {
						k = sd;
					}
				}
				if (i === endYear) {
					// 不能晚于最大日期
					var endMonth = em;
					if (j > endMonth) {
						break;
					} else if (j === endMonth) {
						dayCount = ed;
					}
				}
				const days = [];
				for (k; k <= dayCount; k++) {
					if (i === dy && j === dm && k === dd) {
						// 默认选中日
						md.value[2] = k - 1;
					}
					days.push(k);
				}
				months.push({
					num: j,
					days: days
				});
			}
			years.push({
				num: i,
				months: months
			});
		}
		md.cYears = years;
	}
}

// 显示选择器
function show() {
	init();
	md.open = true;
}
// 隐藏选择器
function hide() {
	md.open = false;
}

// 切换公历/农历
function _onLunar(e) {
	if (md.isLunar !== e) {
		md.isLunar = e;
		if (md.selYear) {
			// 将已选中的日期，转换成切换后的日历格式
			var res;
			if (md.isLunar) {
				// 切换成农历，那就将选中的公历转农历
				res = calendar.solar2lunar(md.selYear.num, md.selMonth.num, md.selDay);
			} else {
				// 切换成公历，那就将选中的农历转公历
				res = calendar.lunar2solar(
					md.selYear.num,
					md.selMonth.num,
					md.selDay,
					md.selMonth.isLeap
				);
			}
			md.defaultDate = new Date(res.cYear, res.cMonth - 1, res.cDay);
		}
		init();
	}
}

// 滚轮变化
function _onChange(e) {
	md.value = e.detail.value;
	setSelectValue();
}

// 修改选中值
function setSelectValue() {
	const v = md.value;

	md.selYear = md.isLunar
		? md.lYears[Math.min(v[0], md.lYears.length - 1)]
		: md.cYears[Math.min(v[0], md.cYears.length - 1)];
	md.selMonth = md.selYear.months[Math.min(v[1], md.selYear.months.length - 1)];
	md.selDay = md.selMonth.days[Math.min(v[2], md.selMonth.days.length - 1)];
}

// 点击确定
function _onSubmit() {
	var res;
	if (md.isLunar) {
		res = calendar.lunar2solar(md.selYear.num, md.selMonth.num, md.selDay, md.selMonth.isLeap);
	} else {
		res = calendar.solar2lunar(md.selYear.num, md.selMonth.num, md.selDay);
	}
	res.isLunar = md.isLunar;

	emit('submit', res);
	hide();
}

// 公历显示补0
function zeroPadding(num) {
	if (md.isLunar) {
		return num;
	}
	return num.toString().padStart(2, '0');
}
</script>

<style scoped lang="scss">
@import './nj-birthday-picker.scss';
</style>
